package com.gooluke.mds.aspect;

import com.gooluke.mds.common.annotation.MapperMultiDataSource;
import com.gooluke.mds.datasource.DatasourceContextHolder;
import com.gooluke.mds.datasource.MultiDataSourceContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;

import java.util.HashMap;
import java.util.Map;

/**
 * @author gooluke
 * description 注解式切面类实现，只针对mapper进行多数据源同时操作，提交、回滚
 * datetime 2025-05-24 4:28
 */
@Aspect
@Component
@Slf4j
public class MapperMultiDataSourceAspect {

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Around("@annotation(mapperMultiDataSource)")
    public Object around(ProceedingJoinPoint joinPoint, MapperMultiDataSource mapperMultiDataSource) throws Throwable {
        int isolationLevel = mapperMultiDataSource.isolationLevel();
        int propagation = mapperMultiDataSource.propagation();
        // 保存原始数据源
        String originalDataSource = DatasourceContextHolder.getDatasource();
        Object result = null;
        Exception exception = null;

        Map<String, TransactionStatus> transactionStatusMap = new HashMap<>();
        try {
            //开启事务
            MultiDataSourceContext.start(transactionManager, mapperMultiDataSource.names(), propagation, isolationLevel);
            log.info("事务开启成功....");
            result = joinPoint.proceed();
        } catch (Exception e) {
            //先不抛出，等回滚完成再抛出异常
            log.error("MultiDataSourceAspect捕获到异常:{}：", e.getMessage());
            exception = e;
        } finally {
            if (exception == null) {
                MultiDataSourceContext.commit();
            } else {
                MultiDataSourceContext.rollback();
            }
            // 如果最开始有设置过数据源，则恢复原始数据源
            if (originalDataSource != null) {
                DatasourceContextHolder.setDatasource(originalDataSource);
            }
            MultiDataSourceContext.clear();
        }
        if (exception != null) {
            throw new RuntimeException(exception);
        }
        return result;
    }
}